#!/usr/bin/env python3
"""
FFmpegVideoPlayer - 基于FFmpeg的视频播放器
提供统���的视频播放接口，具有最佳的Linux兼容性和音视频同步能力
"""

import subprocess
import time
import threading
import queue
import numpy as np
import cv2
from aiortc_custom.logger_config import log_info, log_debug, log_warning, log_error, log_success, log_failure, log_progress, log_connection, log_media, log_stats
from typing import Optional

class FFmpegVideoPlayer:
    """
    基于FFmpeg的视频播放器

    特性：
    - 使用FFmpeg进行视频解码和渲染
    - 自动音视频同步
    - 支持硬件加速
    - 跨平台兼容，特别优化Linux环境
    - 低延迟播放
    """

    def __init__(self, window_title: str = "WebRTC视频", width: int = 640, height: int = 480):
        self.window_title = window_title
        self.width = width
        self.height = height

        # FFmpeg进程相关
        self.ffmpeg_process: Optional[subprocess.Popen] = None
        self.is_running = False

        # 帧缓冲和同步
        self.frame_queue = queue.Queue(maxsize=3)  # 减小队列大小以降低延迟
        self.start_time: Optional[float] = None
        self.frame_count = 0

        # 播放线程
        self.playback_thread: Optional[threading.Thread] = None

    def start(self, width: int = 640, height: int = 480, fps: int = 30) -> bool:
        """
        启动视频播放器

        Args:
            width: 视频宽度
            height: 视频高度
            fps: 目标帧率

        Returns:
            bool: 是否启动成功
        """
        try:
            self.width = width
            self.height = height

            # 构建FFmpeg播放命令，优化性能
            cmd = [
                'ffplay',
                '-window_title', self.window_title,
                '-autoexit',
                '-loglevel', 'error',  # 减少日志输出
                '-f', 'rawvideo',
                '-pixel_format', 'bgr24',  # OpenCV格式
                '-video_size', f'{width}x{height}',
                '-framerate', str(fps),
                '-i', '-'  # 使用标准输入而非pipe:0
            ]

            log_info(f"启动FFmpeg视频播放器: {width}x{height} @ {fps}fps")

            # 启动FFmpeg进程
            self.ffmpeg_process = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.PIPE,  # 保留stderr以便调试
                bufsize=0
            )

            # 等待一小段时间检查进程是否启动成功
            time.sleep(0.1)

            if self.ffmpeg_process.poll() is not None:
                # 进程已退出，获取错误信息
                stderr_output = self.ffmpeg_process.stderr.read().decode('utf-8')
                log_failure(f"FFmpeg视频进程启动失败: {stderr_output}")
                return False

            self.is_running = True
            self.start_time = time.time()

            # 启动播放线程
            self.playback_thread = threading.Thread(target=self._playback_loop, daemon=True)
            self.playback_thread.start()

            log_success("FFmpeg视频播放器启动成功")
            return True

        except Exception as e:
            log_failure(f"FFmpeg视频播放器启动失败: {e}")
            self.is_running = False
            return False

    def write_frame(self, frame: np.ndarray, timestamp: Optional[float] = None) -> None:
        """
        写入视频帧

        Args:
            frame: 视频帧数据 (BGR24格式的numpy数组)
            timestamp: 可选的时间戳，用于同步
        """
        if not self.is_running or self.ffmpeg_process is None:
            return

        try:
            # 确保帧数据格式正确
            if frame is None or frame.size == 0:
                return

            # 转换为正确的格式（如果需要）
            if frame.dtype != np.uint8:
                frame = frame.astype(np.uint8)

            # 确保是BGR24格式
            if len(frame.shape) == 2:
                # 灰度图转BGR
                frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
            elif frame.shape[2] == 4:
                # RGBA转BGR
                frame = cv2.cvtColor(frame, cv2.COLOR_RGBA2BGR)
            elif frame.shape[2] == 1:
                # 单通道转BGR
                frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)

            # 调整大小（如果需要）
            if frame.shape[1] != self.width or frame.shape[0] != self.height:
                frame = cv2.resize(frame, (self.width, self.height))

            # 移除有问题的同步控制，让FFmpeg自动处理时间同步
            # 同步控制
            # if timestamp is not None:
            #     current_time = time.time()
            #     target_time = self.start_time + timestamp
            #     if current_time < target_time:
            #         time.sleep(target_time - current_time)

            # 将帧放入队列
            try:
                self.frame_queue.put_nowait(frame.copy())
            except queue.Full:
                # 队列满了，丢弃旧帧
                try:
                    self.frame_queue.get_nowait()
                    self.frame_queue.put_nowait(frame.copy())
                except queue.Empty:
                    pass

            self.frame_count += 1

        except Exception as e:
            log_warning(f"写入视频帧失败: {e}")

    def _playback_loop(self) -> None:
        """播放循环线程"""
        consecutive_errors = 0
        max_consecutive_errors = 5

        while self.is_running:
            try:
                frame = self.frame_queue.get(timeout=0.1)

                if self.ffmpeg_process and self.ffmpeg_process.stdin and not self.ffmpeg_process.stdin.closed:
                    # 写入帧数据到FFmpeg
                    self.ffmpeg_process.stdin.write(frame.tobytes())
                    self.ffmpeg_process.stdin.flush()
                    consecutive_errors = 0  # 重置错误计数

            except queue.Empty:
                continue
            except (BrokenPipeError, ConnectionError) as e:
                consecutive_errors += 1
                log_warning(f"FFmpeg视频管道断开: {e}")
                if consecutive_errors >= max_consecutive_errors:
                    log_error("连续管道断开错误，停止视频播放")
                    self.is_running = False
                    break
                # 短暂等待后继续
                time.sleep(0.1)
            except Exception as e:
                consecutive_errors += 1
                log_warning(f"视频播放循环错误: {e}")
                if self.ffmpeg_process and self.ffmpeg_process.poll() is not None:
                    log_error("FFmpeg视频进程已终止")
                    break
                if consecutive_errors >= max_consecutive_errors:
                    log_error("连续播放错误，停止视频播放")
                    self.is_running = False
                    break
                time.sleep(0.1)

    def stop(self) -> None:
        """停止视频播放器"""
        log_info("正在停止FFmpeg视频播放器...")

        self.is_running = False

        # 停止播放线程
        if self.playback_thread and self.playback_thread.is_alive():
            self.playback_thread.join(timeout=1.0)

        # 终止FFmpeg进程
        if self.ffmpeg_process:
            try:
                if self.ffmpeg_process.stdin:
                    self.ffmpeg_process.stdin.close()
                self.ffmpeg_process.terminate()
                self.ffmpeg_process.wait(timeout=2.0)
            except Exception:
                try:
                    self.ffmpeg_process.kill()
                except Exception:
                    pass
            finally:
                self.ffmpeg_process = None

        # 清空队列
        while not self.frame_queue.empty():
            try:
                self.frame_queue.get_nowait()
            except queue.Empty:
                break

        log_success("FFmpeg视频播放器已停止")

    def get_stats(self) -> dict:
        """获取播放统计信息"""
        return {
            'is_running': self.is_running,
            'frame_count': self.frame_count,
            'window_size': f'{self.width}x{self.height}',
            'queue_size': self.frame_queue.qsize(),
            'running_time': time.time() - self.start_time if self.start_time else 0
        }

    def __enter__(self):
        """上下文管理器支持"""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器支持"""
        self.stop()